﻿using System;
using UnityEngine;
using UnityEngine.UI;
using System.Reflection;
using System.Collections;
using System.Threading.Tasks;
using UnityEngine.EventSystems;
using Object = UnityEngine.Object;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem.UI;
#endif

namespace Miao.UI
{
    /// <summary>
    /// 基于URP+Addressable的UI管理
    /// </summary>
    public static class UIManager
    {
        /// <summary>
        /// 表示当前UI管理器是否开启
        /// </summary>
        public static bool isEnable { get; private set; }
        /// <summary>
        /// 获取UI管理器的根 <see cref="Canvas"/>
        /// </summary>
        public static Canvas mainCanvas { get; private set; }
        /// <summary>
        /// 获取UI管理器的渲染 <see cref="Camera"/>
        /// </summary>
        public static Camera UICamera { get; private set; }

        public static readonly RectTransform canvasTransfrom;
        public static readonly CanvasScaler canvasScaler;

        private static readonly GameObject canvasGameObject;
        private static readonly GameObject cameraGameObject;

        public static readonly RectTransform ViewLayer;//整个场景只有一个View
        public static readonly RectTransform WindowLayer;//整个场可以有很多个Window
        public static Vector2 referenceResolution
        {
            get
            {
                return canvasScaler.referenceResolution;
            }
            set
            {
                canvasScaler.referenceResolution = value;
            }
        }
        static UIManager()
        {
            isEnable = true;
            //添加组件
            canvasGameObject = new GameObject("UICanvas");
            canvasGameObject.layer = LayerMask.NameToLayer("UI");
            Object.DontDestroyOnLoad(canvasGameObject);
            mainCanvas = canvasGameObject.AddComponent<Canvas>();
            canvasGameObject.AddComponent<GraphicRaycaster>();
            canvasScaler = canvasGameObject.AddComponent<CanvasScaler>();
            canvasTransfrom = canvasGameObject.GetComponent<RectTransform>();
            //添加事件系统

            GameObject eventSystemGameObject = new GameObject("EventSystem"); //{ hideFlags = HideFlags.HideInHierarchy };



            if(GameObject.FindAnyObjectByType<EventSystem>()==null)
            {
                eventSystemGameObject.AddComponent<EventSystem>();
            }
#if ENABLE_INPUT_SYSTEM
            ///新事件系统
            eventSystemGameObject.AddComponent<InputSystemUIInputModule>();
#else
            ///旧版事件系统
            eventSystemGameObject.AddComponent<StandaloneInputModule>();
#endif
            Object.DontDestroyOnLoad(eventSystemGameObject);


            //设置分辨率
            //canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
            //Resolution currentResolution = Screen.currentResolution;
            //canvasScaler.referenceResolution = new Vector2(currentResolution.width, currentResolution.height);
            //创建UI相机，现在是固定画布UI大小
            cameraGameObject = new GameObject("UICamera");
            canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
            canvasScaler.referenceResolution = new Vector2(1920,1080);
            //Resolution currentResolution = Screen.currentResolution;
            //cameraGameObject.hideFlags = HideFlags.HideInHierarchy;
            Object.DontDestroyOnLoad(cameraGameObject);
            UICamera = cameraGameObject.AddComponent<Camera>();
            UICamera.clearFlags = CameraClearFlags.Depth;
            UICamera.cullingMask = 1 << LayerMask.NameToLayer("UI");
            UICamera.orthographic = true;
            //绑定相机
            mainCanvas.planeDistance = 1;
            mainCanvas.worldCamera = UICamera;
            mainCanvas.renderMode = RenderMode.ScreenSpaceCamera;
            //创建层级子类
            WindowLayer = new GameObject(nameof(WindowLayer), typeof(RectTransform)).GetComponent<RectTransform>();
            ViewLayer = new GameObject(nameof(ViewLayer), typeof(RectTransform)).GetComponent<RectTransform>();
            InitLayer(WindowLayer);
            InitLayer(ViewLayer);
            SetCameraStack();
        }

        public static void Init()
        {

        }

        static void InitLayer(RectTransform layer)
        {
            layer.SetParent(canvasTransfrom, false);
            layer.anchorMin = Vector3.zero;
            layer.anchorMax = new Vector3(1, 1);
            layer.offsetMin = Vector3.zero;
            layer.offsetMax = Vector3.zero;
        }

        static public void SetCameraStack(int index)
        {
            if (GraphicsSettings.currentRenderPipeline != null)
            {
                UniversalAdditionalCameraData universalAdditionalCameraData = UICamera.GetUniversalAdditionalCameraData();
                universalAdditionalCameraData.renderType = CameraRenderType.Overlay;
                if (!Camera.main.GetUniversalAdditionalCameraData().cameraStack.Contains(UICamera))
                {
                    Camera.main.GetUniversalAdditionalCameraData().cameraStack.Add(UICamera);
                }
                universalAdditionalCameraData.SetRenderer(index);
            }

        }

        static public void SetCameraStack()
        {
            if (GraphicsSettings.currentRenderPipeline != null)
            {
                UniversalAdditionalCameraData universalAdditionalCameraData = UICamera.GetUniversalAdditionalCameraData();
                universalAdditionalCameraData.renderType = CameraRenderType.Overlay;
                if (!Camera.main.GetUniversalAdditionalCameraData().cameraStack.Contains(UICamera))
                {
                    Camera.main.GetUniversalAdditionalCameraData().cameraStack.Add(UICamera);
                }
            }
        }
        /// <summary>
        /// 启用 <see cref="UIManager"/>
        /// </summary>
        public static void Enable()
        {
            if (isEnable) return;
            isEnable = true;
            canvasGameObject.SetActive(true);
            cameraGameObject.SetActive(true);
        }
        /// <summary>
        /// 禁用 <see cref="UIManager"/>
        /// </summary>
        public static void Disable()
        {
            if (!isEnable) return;
            isEnable = false;
            canvasGameObject.SetActive(false);
            cameraGameObject.SetActive(false);
        }
        /// <summary>
        /// 设置UI分辨率
        /// </summary>
        /// <param name="resolution"></param>
        public static void SetResolution(Vector2 resolution)
        {
            canvasScaler.referenceResolution = resolution;
        }
        /// <summary>
        /// 设置宽高适应
        /// </summary>
        /// <param name="widthOrHeight"></param>
        public static void SetResolutionMatch(float widthOrHeight)
        {
            canvasScaler.matchWidthOrHeight = widthOrHeight;
        }
        private static async Task<T> OpenAsyncInternal<T>(Transform parent) where T : UIPanel, new()
        {
            Type uiType = typeof(T);
            SourcesPathAttribute pathAttribute = uiType.GetCustomAttribute<SourcesPathAttribute>();
#if UNITY_EDITOR
            if (pathAttribute == null) Debug.LogError($"UI {uiType.Name} 没有 {nameof(SourcesPathAttribute)} 特性!");
#endif
            //GameObject panelInstane = await Addressables.LoadAssetAsync<GameObject>(pathAttribute.path).Task;
            GameObject panelInstane = await Addressables.InstantiateAsync(pathAttribute.path).Task;//读取并直接实例化资产
#if UNITY_EDITOR
            if (!panelInstane) Debug.LogError($"打开UI失败 路径 {pathAttribute.path} 不存在!");
#endif
            T panel = panelInstane.GetComponent<T>();
            panel.rectTransform = panelInstane.transform as RectTransform;
            if (parent == null)
            {
                UILayerAttribute depthAttribute = uiType.GetCustomAttribute<UILayerAttribute>();
                if (depthAttribute != null)
                {
                    switch (depthAttribute.layer)
                    {
                        case Layer.WindowLayer:
                            panel.rectTransform.SetParent(WindowLayer, false);
                            break;
                        case Layer.ViewLayer:
                            panel.rectTransform.SetParent(ViewLayer, false);
                            break;
                        case Layer.TempLayer:
                            panel.rectTransform.SetParent(canvasTransfrom, false);
                            break;
                    }
                    panel.rectTransform.SetSiblingIndex(depthAttribute.depth);
                }
                else
                {
                    panel.rectTransform.SetParent(canvasTransfrom, false);
                }
                
            }
            else
            {
                panel.rectTransform.SetParent(parent, false);
            }
            await panel.OnCreate();
            return panel;
        }


        /// <summary>
        /// 打开带有入场效果的Panel
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="ShowMotion"></param>
        /// <param name="HideMotion"></param>
        /// <returns></returns>
        public static async Task<T> OpenMotionAsync<T>(BaseUIMotion ShowMotion, BaseUIMotion HideMotion) where T : UIMotionPanel, new()
        {
           return await OpenMotionAsync<T>(canvasTransfrom, ShowMotion, HideMotion);
        }

        public static async Task<T> OpenMotionAsync<T>(BaseUIMotion ShowMotion, BaseUIMotion HideMotion, bool show = true) where T : UIMotionPanel, new()
        {
            return await OpenMotionAsync<T>(canvasTransfrom, ShowMotion, HideMotion, show);
        }


        /// <summary>
        /// 打开带有入场效果的Panel
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="ShowMotion"></param>
        /// <param name="HideMotion"></param>
        /// <returns></returns>
        public static async Task<T> OpenMotionAsync<T>(Transform parent,BaseUIMotion ShowMotion, BaseUIMotion HideMotion,bool show = true) where T : UIMotionPanel, new()
        {
            var panel = await OpenAsyncInternal<T>(parent);
            panel.ShowMotion = ShowMotion;
            panel.HideMotion = HideMotion;
            if (show)
            {
                await panel.ShowAsync();
            }
            else
            {
                panel.gameObject.SetActive(false);
            }
            return panel;
        }

        public static Task<T> OpenAsync<T>(Transform parent) where T : UIPanel, new()
        {
            return OpenAsync<T>(parent, true);
        }

        /// <summary>
        /// 以任务异步的方式打开一个UI面板
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Task<T> OpenAsync<T>(bool ShowNow = true) where T : UIPanel, new()
        {
            return OpenAsync<T>(null, ShowNow);
        }

        /// <summary>
        /// 打开一个UI
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static async Task<T> OpenAsync<T>(Transform parent, bool ShowNow) where T : UIPanel, new()
        {
            T panel = await OpenAsyncInternal<T>(parent);
            if (ShowNow)
            {
                panel.Show();
            }
            else
            {
                panel.Hide();
            }
            return panel;
        }

        /// <summary>
        /// 关闭一个UI面板
        /// </summary>
        /// <param name="panel"></param>
        internal static void ClosePanel(UIPanel panel)
        {
            Addressables.ReleaseInstance(panel.gameObject);
            //Object.Destroy(panel.transform.gameObject);
        }
    }


}